/**
@author		Jong Min, Lee
@date		  01/23/2014
@brief		tool data administrator

copyright(c) Tae Young Soft. All right reserved. 2014
*/
#include "stdafx.h"
#include "Taurus_ToolData/ToolDataAdmin.h"

#include <algorithm>

#include "Taurus_Viewer/CmdIDs.h"

#include "Taurus_ToolData/Resource.h"

#define IDS_COMMON_TOOL_GROUP         _T("Common")
#define IDS_ANNOTATION_TOOL_GROUP     _T("Annotation")
#define IDS_OD_TOOL_GROUP             _T("OD")
#define IDS_ETC_TOOL_GROUP            _T("ETC")

CToolDataAdmin* CToolDataAdmin::m_pInstance = NULL;

extern HINSTANCE getThisModuleHandle();

CToolDataAdmin::CToolDataAdmin()
{}

CToolDataAdmin::~CToolDataAdmin()
{
  destroyToolData();
}

CToolDataAdmin* CToolDataAdmin::getInstance()
{
  if(m_pInstance == NULL)
    _TRY_ALLOC(m_pInstance, CToolDataAdmin);

  return m_pInstance;
}

DWORD CToolDataAdmin::loadData(BOOL bLoad2K)
{
  destroyToolData();

  //change resource instance handle
  HINSTANCE hOldInst = ::AfxGetResourceHandle();
  ::AfxSetResourceHandle(getThisModuleHandle());

  //create common tool data
  DWORD dwError = createCommonToolData(bLoad2K);
  if(dwError != ERROR_SUCCESS)
  {
    goto finish_load_data;
  }

  dwError = createAnnotationToolData(bLoad2K);
  if(dwError != ERROR_SUCCESS)
  {
    goto finish_load_data;
  }

  dwError = createODToolData(bLoad2K);
  if(dwError != ERROR_SUCCESS)
  {
    goto finish_load_data;
  }

  dwError = createETCToolData(bLoad2K);
  if(dwError != ERROR_SUCCESS)
  {
    goto finish_load_data;
  }

finish_load_data:
  ::AfxSetResourceHandle(hOldInst);
  if(dwError != ERROR_SUCCESS)
  {
    destroyToolData();
  }

  return dwError;
}

const CToolData* CToolDataAdmin::search_CmdID(UINT uCmdID) const
{
  for(auto pos = m_mapToolGroups.begin(), e = m_mapToolGroups.end(); pos != e; ++pos)
  {
    auto res = find_if(pos->second->begin(), pos->second->end(),
      [&uCmdID](CToolData* pToolData)
    {
      return (pToolData->uCmdID == uCmdID);
    });

    if(res !=  pos->second->end())
      return (*res);
  }

  return NULL;
}

const CToolData* CToolDataAdmin::search_ID(UINT uID) const
{
  for(auto pos = m_mapToolGroups.begin(), e = m_mapToolGroups.end(); pos != e; ++pos)
  {
    auto res = find_if(pos->second->begin(), pos->second->end(),
      [&uID](CToolData* pToolData)
    {
      return (pToolData->uID == uID);
    });

    if(res != pos->second->end())
      return *res;
  }

  return NULL;
}

unsigned CToolDataAdmin::getNumToolData(const TCHAR* pszGroupName) const
{
  if(pszGroupName == NULL)
    return 0;

  auto pos = m_mapToolGroups.find(pszGroupName);
  if(pos != m_mapToolGroups.end())
    return (pos->second->size());

  return 0;
}

const TCHAR* CToolDataAdmin::getGroupName(unsigned nIndex) const
{
  if(nIndex >= m_mapToolGroups.size())
    return NULL;

  auto pos = m_mapToolGroups.begin();
  std::advance(pos, nIndex);
  return (pos->first);
}

DWORD CToolDataAdmin::createDefaultToolboxData(std::list<CToolboxData*>& cContainer) const
{
  const TCHAR* arrGroupNames[] =
  {
    IDS_COMMON_TOOL_GROUP,
    IDS_ANNOTATION_TOOL_GROUP,
    IDS_OD_TOOL_GROUP,
    IDS_ETC_TOOL_GROUP
  };

  std::list<CToolboxData*> temp;
  CToolboxData* pToolboxData = NULL;

  DWORD dwError = ERROR_SUCCESS;
  int nCount = sizeof(arrGroupNames) / sizeof(const TCHAR*);
  for(int i = 0; i < nCount; ++i)
  {
    dwError = createDefaultToolboxData(arrGroupNames[i], pToolboxData);
    if(dwError != ERROR_SUCCESS)
      break;

    _TRY_BEGIN
    temp.push_back(pToolboxData);
    _CATCH_ALL
    _DELETE(pToolboxData);
    dwError = ERROR_NOT_ENOUGH_MEMORY;
    break;
    _CATCH_END
  }

  if(dwError == ERROR_SUCCESS)
  {
    _TRY_BEGIN
    cContainer.insert(cContainer.end(), temp.begin(), temp.end());
    _CATCH_ALL
    dwError = ERROR_NOT_ENOUGH_MEMORY;
    _CATCH_END
  }

  if(dwError != ERROR_SUCCESS)
  {
    for_each(temp.begin(), temp.end(),
      [](CToolboxData* pToolboxData)
    {
      _DELETE(pToolboxData);
    });
    temp.clear();
    return dwError;
  }

  return ERROR_SUCCESS;
}

DWORD CToolDataAdmin::createCommonToolData(BOOL bLoad2K)
{
  UINT uCmdIDs[] =
  {
    TV_CMD_SELECTOR,              //selet mode
    TV_CMD_CONT_PAN,              //continuous pan
    TV_CMD_CONT_ZOOM,             //continous zoom
    TV_CMD_ROI_ZOOM,              //roi zoom
    TV_CMD_CONT_WWL,              //continuos wwl
    TV_CMD_ROI_AUTO_WWL,          //roi auto wwl
    TV_CMD_MAGNIFICATION,         //magnification
    TV_CMD_FIT,                   //fit
    TV_CMD_H_FLIP,                //flip horizontally
    TV_CMD_V_FLIP,                //flip vertically
    TV_CMD_ROTATE_C_90,           //rotate colockwise through 90
    TV_CMD_ROTATE_CC_90,          //rotate counterclockwise through 90
    TV_CMD_ROTATE_180,            //rotate 180
    TV_CMD_INVERT_COLOR,          //invert color
    TV_CMD_SELECT_ALL,            //select all
    TV_CMD_REVERSE_SELECT,        //select inverse
    TV_CMD_SHARPEN_FILTER,        //sharepen filter
    TV_CMD_AVERAGE_FILTER,        //average filter
    TV_CMD_PESUO_COLOR,           //pesudo color
    TV_CMD_PRINT,                 //print
    TV_CMD_DICTATION,             //dictation
    TV_CMD_PLAY_DICTATION,        //play dictation
    TV_CMD_RESET,                 //reset
    TV_CMD_REFRESH_STUDY,         //refresh study
    TV_CMD_KEY_IMAGE,             //key image
    TV_CMD_PATIENT_HISTORY,       //patient history
    TV_CMD_COPY_IMG_CLIPBOARD,    //copy image to clipboard
    TV_CMD_CLOSE_STUDY,           //close study
    TV_CMD_SAVE_STUDY            //save study
  };

  UINT uIDs[] =
  {
    IDC_BTN_COMMON_SELECTOR,              //select mode
    IDC_BTN_COMMON_PAN,                   //continuous pan
    IDC_BTN_COMMON_ZOOM,                  //continuous zoom
    IDC_BTN_COMMON_ROI_ZOOM,              //roi zoom
    IDC_BTN_COMMON_WWL,                   //continous wwl
    IDC_BTN_COMMON_ROI_WWL,               //roi auto wwl
    IDC_BTN_COMMON_MAGNIFICATION,         //magnification
    IDC_BTN_COMMON_FIT,                   //fit
    IDC_BTN_COMMON_H_FLIP,                //flip horizontally
    IDC_BTN_COMMON_V_FLIP,                //flip vertically
    IDC_BTN_COMMON_ROTATE_C_90,           //rotate clockwise 90
    IDC_BTN_COMMON_ROTATE_CC_90,          //rotate counterclockwise 90 
    IDC_BTN_COMMON_ROATE_180,             //rotate 180
    IDC_BTN_COMMON_INVERT_COLOR,          //invert color
    IDC_BTN_COMMON_SELECT_ALL,            //select all
    IDC_BTN_COMMON_REVERSE_SELECT,        //select inverse
    IDC_BTN_COMMON_SHARPEN_FILTER,        //sharpen filter
    IDC_BTN_COMMON_AVERAGE_FILTER,        //average filter
    IDC_BTN_COMMON_PESUDO,                //pesudo color
    IDC_BTN_COMMON_PRINT,                 //print
    IDC_BTN_COMMON_DICTATION,             //dictation
    IDC_BTN_COMMON_PLAY_DICTATION,        //play dictation
    IDC_BTN_COMMON_RESET,                 //reset
    IDC_BTN_COMMON_REFRESH_STUDY,         //refresh study info
    IDC_BTN_COMMON_KEY_IMAGE,             //key image
    IDC_BTN_COMMON_PATIENT_HISTORY,       //pateint history
    IDC_BTN_COMMON_COPY_IMG_CLIPBOARD,    //copy image to clipboard
    IDC_BTN_COMMON_CLOSE_STUDY,           //close study
    IDC_BTN_COMMON_SAVE_STUDY             //save study
  };

  BOOL bNeedMouseInputs[] =
  {
    TRUE,          //select mode
    TRUE,          //continuous pan
    TRUE,          //continuous zoom
    TRUE,          //roi zoom
    TRUE,          //continuous wwl
    TRUE,          //roi auto wwl
    TRUE,          //magnification
    FALSE,         //fit
    FALSE,         //flip horizontally
    FALSE,         //flip vertically
    FALSE,         //rotate clockwise 90
    FALSE,         //rotate counterclosewise 90
    FALSE,         //rotate 180
    FALSE,         //invert color
    FALSE,         //select all
    FALSE,         //select inverse
    FALSE,         //sharpen filter
    FALSE,         //average filter
    FALSE,         //pesudo color
    FALSE,         //print
    FALSE,         //dictation
    FALSE,         //play dictation
    FALSE,         //reset
    FALSE,         //refresh study info
    TRUE,          //key image
    FALSE,         //patietn history
    FALSE,         //copy image to clipboard
    FALSE,         //close study
    FALSE          //save study
  };

  // TODO(Jong Min, Lee): support multi language
  CString strNames[] =
  {
    _T("Selector"),                        //select mode
    _T("Pan"),                             //continuous pan
    _T("Zoom"),                            //continuous zomm
    _T("ROI Zoom"),                        //roi zoom
    _T("Windowing"),                       //continuous wwl
    _T("ROI Auto Windowing"),              //roi auto wwl
    _T("Magnification"),                   //magnification
    _T("Filt"),                            //fit
    _T("Flip horizontal"),                 //flip horizontal
    _T("Flip vertical"),                   //flip vertical
    _T("Rotate right 90"),                 //rotate clockwise 90
    _T("Rotate left 90"),                  //rotate counterclockwise 90
    _T("Rotate right 180"),                //rotate 180
    _T("Invert color"),                    //invert color
    _T("Select all"),                      //select all
    _T("Select all inverse"),              //select inverse
    _T("Sharpen filter"),                  //sharpen filter
    _T("Avrage filter"),                   //average filter
    _T("Pseudo"),                          //pesudo color
    _T("Print"),                           //print
    _T("Dictation"),                       //dictation
    _T("Play dictation"),                  //play dictation
    _T("Reset"),                           //Reset
    _T("Refresh study"),                   //Refresh
    _T("Key image"),                       //key image
    _T("Patient's history"),               //patient history
    _T("Copy clipboard"),                  //copy image to clipboard
    _T("Close"),                           //close study
    _T("Save")
  };

  std::vector<CToolData*>* arrCommonToolData = NULL;
  _TRY_ALLOC(arrCommonToolData, std::vector<CToolData*>);
  if(arrCommonToolData == NULL)
    return ERROR_NOT_ENOUGH_MEMORY;

  int nNumToolData = sizeof(uIDs) / sizeof(UINT);
  _TRY_BEGIN
  arrCommonToolData->reserve(nNumToolData);
  _CATCH_ALL
  _DELETE(arrCommonToolData);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  DWORD dwError = ERROR_SUCCESS;
  for(int i = 0; i < nNumToolData; ++i)
  {
    CToolData* pToolData = NULL;
    _TRY_ALLOC(pToolData, CToolData);
    if(pToolData == NULL)
    {
      dwError = ERROR_NOT_ENOUGH_MEMORY;
      break;
    }

    pToolData->strName          = strNames[i];
    pToolData->uID              = uIDs[i];
    pToolData->uCmdID           = uCmdIDs[i];
    pToolData->bNeedMouseInput  = bNeedMouseInputs[i];
    pToolData->hBitmap          = NULL;
    pToolData->hBitmap2K        = NULL;

    arrCommonToolData->push_back(pToolData);
  }

  if(dwError!= ERROR_SUCCESS)
  {
    for_each(arrCommonToolData->begin(), arrCommonToolData->end(),
      [](CToolData* pToolData) { _DELETE(pToolData); });
    _DELETE(arrCommonToolData);
    return dwError;
  }

  _TRY_BEGIN
  m_mapToolGroups[IDS_COMMON_TOOL_GROUP] = arrCommonToolData;
  _CATCH_ALL
  for_each(arrCommonToolData->begin(), arrCommonToolData->end(),
    [](CToolData* pToolData) { _DELETE(pToolData); });
  _DELETE(arrCommonToolData);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  return ERROR_SUCCESS;
}

DWORD CToolDataAdmin::createAnnotationToolData(BOOL bLoad2K)
{
  UINT uCmdIDs[] = 
  {
    TV_CMD_ANNOTATION_LINE,           //annotation line
    TV_CMD_ANNOTATION_ARROW,          //annotation arrow
    TV_CMD_ANNOTATION_RECT,           //annotation rect
    TV_CMD_ANNOTATION_CIRCLE,         //annotation circle
    TV_CMD_ANNOTATION_ELLIPSE,        //annotation ellipse
    TV_CMD_ANNOTATION_POLYGON,        //annotation polygon
    TV_CMD_ANNOTATION_CURVE,          //annotation curve
    TV_CMD_ANNOTATION_FREE_DRAW,      //annoatation free draw
    TV_CMD_ANNOTATION_TEXT,           //annotation text
    TV_CMD_ANNOTATION_MEMO,           //annotation memo
    TV_CMD_ANNOTATION_MARKING,        //annotation marking
    TV_CMD_MEASURE_CALIPER,           //measure caliper
    TV_CMD_MEASURE_RATIO,             //measure ratio
    TV_CMD_MEASURE_ANGLE,             //measure angle
    TV_CMD_MEASURE_COBBS_ANLGE,       //measure cobb's angle
    TV_CMD_MEASURE_CT_RATIO,          //measure ct ratio
    TV_CMD_MEASURE_LIMB_LD,           //measure limb ld
    TV_CMD_MEASURE_LENS,              //measure lens
    TV_CMD_MEASURE_CALIBRATE,         //measure calibrate
    TV_CMD_SPINE_LABELING,            //spine label
    TV_CMD_ROI_CIRCLE,                //roi circle
    TV_CMD_ROI_ELLIPSE,               //roi ellipse
    TV_CMD_ROI_RECT,                  //roi rect
    TV_CMD_ROI_POLYGON,               //roi polygon
    TV_CMD_ROI_CURVE,                 //roi curve
    TV_CMD_ROI_FREE_DRAW,             //roi free draw
    TV_CMD_SHUTTER_CIRCLE,            //shutter circle
    TV_CMD_SHUTTER_ELLIPSE,           //shutter ellipse
    TV_CMD_SHUTTER_RECT,              //shutter rectangle
    TV_CMD_SHUTTER_POLYGON,           //shutter polygon
    TV_CMD_SHUTTER_CURVE,             //shutter curve
    TV_CMD_SHUTTER_FREE_DRAW          //shutter free draw
  };

  UINT uIDs[] =
  {
    IDC_BTN_ANNOTATION_LINE,          //annotation line
    IDC_BTN_ANNOTATION_ARROW,         //annotation arrow
    IDC_BTN_ANNOTATION_RECT,          //annotation rect
    IDC_BTN_ANNOTATION_CIRCLE,        //annotation circle
    IDC_BTN_ANNOTATION_ELLIPSE,       //annotation ellipse
    IDC_BTN_ANNOTATION_POLYGON,       //annotation polygon
    IDC_BTN_ANNOTATION_CURVE,         //annotation curve
    IDC_BTN_ANNOTATION_FREE_DRAW,     //annotation free draw
    IDC_BTN_ANNOTATION_TEXT,          //annotation text
    IDC_BTN_ANNOTATION_MEMO,          //annotation memod
    IDC_BTN_ANNOTATION_MARKING,       //annotation marking
    IDC_BTN_MEASURE_CALIPER,          //measure cliper
    IDC_BTN_MEASURE_RATIO,            //measure ratio
    IDC_BTN_MEASURE_ANGLE,            //measure angle
    IDC_BTN_MEASURE_COBBS_ANGLE,      //measrue cobb'angle
    IDC_BTN_MEASURE_CT_RATIO,         //measure ct ratio
    IDC_BTN_MEASURE_LIMB_LD,          //measure limb ld
    IDC_BTN_MEASURE_LENS,             //measure lens
    IDC_BTN_MEASURE_CALIBRATE,        //measure calibrate
    IDC_BTN_SPINE_LABEL,              //spine labeling
    IDC_BTN_ROI_CIRCLE,               //roi circle
    IDC_BTN_ROI_ELLIPSE,              //roi ellpise
    IDC_BTN_ROI_RECT,                 //roi rectangle
    IDC_BTN_ROI_POLYGON,              //roi poloygon
    IDC_BTN_ROI_CURVE,                //roi curve
    IDC_BTN_ROI_FREE_DRAW,            //roi free draw
    IDC_BTN_SHUTTER_CIRCLE,           //shutter circle
    IDC_BTN_SHUTTER_ELLIPSE,          //shutter ellipse
    IDC_BTN_SHUTTER_RECT,             //shutter rectangle
    IDC_BTN_SHUTTER_POLYGON,          //shutter polygon
    IDC_BTN_SHUTTER_CURVE,            //shutter curve
    IDC_BTN_SHUTTER_FREE_DRAW         //shutter free draw
  };

  // TODO(Jong Min, Lee): support multilanguage
  CString strNames[] =
  {
    _T("Line"),                         //annotation line
    _T("Arrow"),                        //annotation arrow
    _T("Rectangle"),                    //annotation rectangle
    _T("Circle"),                       //annnotation circle
    _T("Ellipse"),                      //annotation ellipse
    _T("Polygon"),                      //annotation polygon
    _T("Curve"),                        //annotation curve
    _T("Free draw"),                    //annotation free draw
    _T("Text"),                         //annotation tect
    _T("Memo"),                         //annotation memo
    _T("Marking"),                      //annotation marking
    _T("Caliper"),                      //measure caliper
    _T("Ratio"),                        //measrue ratio
    _T("Angle"),                        //measure angle
    _T("Cobb's angle"),                 //measure cobb's angle
    _T("CT Ratio"),                     //measure ct ratio
    _T("Limb LD"),                      //measure limb ld
    _T("Lens/Housfield/SUV"),           //measure lens
    _T("Calibrate"),                    //measure calibrate
    _T("Spine label"),                  //measure spine label
    _T("ROI Circle"),                   //roi circle
    _T("ROI Ellipse"),                  //roi ellipse
    _T("ROI Rectangle"),                //roi rectangle
    _T("ROI Polygon"),                  //roi polyogon
    _T("ROI Curve"),                    //roi curve
    _T("ROI Free draw"),                //roi free draw
    _T("Circle shutter"),               //shutter circle
    _T("Ellipse shutter"),              //ellipse shutter
    _T("Rectangle shutter"),            //shutter rectangle
    _T("Polygon shutter"),              //polygon shutter
    _T("Curve shutter"),                //curve shutter
    _T("Free draw shutter")             //free draw shutter
  };

  std::vector<CToolData*>* arrTools = NULL;
  _TRY_ALLOC(arrTools, std::vector<CToolData*>)
    if(arrTools == NULL)
      return ERROR_NOT_ENOUGH_MEMORY;

  int nCount = sizeof(uIDs) / sizeof(UINT);
  try
  {
    arrTools->reserve(nCount);
  }
  catch(const std::bad_alloc&)
  {
    _DELETE(arrTools);
    return ERROR_NOT_ENOUGH_MEMORY;
  }

  DWORD dwError = ERROR_SUCCESS;
  for(int i = 0; i < nCount; i++)
  {
    CToolData* pToolData = NULL;
    _TRY_ALLOC(pToolData, CToolData)
    if(pToolData == NULL)
    {
      dwError = ERROR_NOT_ENOUGH_MEMORY;
      break;
    }

    pToolData->strName         = strNames[i];
    pToolData->uID             = uIDs[i];
    pToolData->uCmdID          = uCmdIDs[i];
    pToolData->bNeedMouseInput = TRUE;
    pToolData->hBitmap         = NULL;
    pToolData->hBitmap2K       = NULL;

    arrTools->push_back(pToolData);
  }

  if(dwError != ERROR_SUCCESS)
  {
    for_each(arrTools->begin(), arrTools->end(),
      [](CToolData* pToolData) { _DELETE(pToolData); });
    _DELETE(arrTools);
    return dwError;
  }

  _TRY_BEGIN
    m_mapToolGroups[IDS_ANNOTATION_TOOL_GROUP] = arrTools;
  _CATCH_ALL
    for_each(arrTools->begin(), arrTools->end(),
    [](CToolData* pToolData) { _DELETE(pToolData); });
  _DELETE(arrTools);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  return dwError;
}

DWORD CToolDataAdmin::createODToolData(BOOL bLoad2K)
{
  UINT uCmdIDs[] =
  {
    TV_CMD_CROSS_LINK,                //cross link
    TV_CMD_SCOUT_IMAGE,               //scout image
    TV_CMD_3D_CURSOR,                 //3d cursor
    TV_CMD_CUT_IMAGES,                //cut images
    TV_CMD_PASTE_FORWARD,             //paste forward
    TV_CMD_PASTE_BACKWARD             //pase backward
  };

  UINT uIDs[] =
  {
    IDC_BTN_OD_CROSS_LINK,            //cross link
    IDC_BTN_OD_SCOUT_IMAGE,           //scout image
    IDC_BTN_OD_3D_CURSOR,             //3d cursor
    IDC_BTN_OD_CUT_IMAGES,            //cut images
    IDC_BTN_OD_PASTE_FORWARD,          //paste forward
    IDC_BTN_OD_PASTE_BACKWARD         //paste backward
  };

  CString strNames[] =
  {
    _T("Cross link"),                   //cross link
    _T("Scout image"),                  //scout image
    _T("3D Cursor"),                    //3d cursor
    _T("Cut images"),                   //CUt images
    _T("Paste forward"),                //paste forward
    _T("Paste backward")                //paste backward
  };

  std::vector<CToolData*>* arrTools = NULL;
  _TRY_ALLOC(arrTools, std::vector<CToolData*>)
    if(arrTools == NULL)
      return ERROR_NOT_ENOUGH_MEMORY;

  int nCount = sizeof(uIDs) / sizeof(UINT);
  _TRY_BEGIN
  arrTools->reserve(nCount);
  _CATCH_ALL
  _DELETE(arrTools);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  DWORD dwError = ERROR_SUCCESS;
  for(int i = 0; i < nCount; i++)
  {
    CToolData* pToolData = NULL;
    _TRY_ALLOC(pToolData, CToolData)
    if(pToolData == NULL)
    {
      dwError = ERROR_NOT_ENOUGH_MEMORY;
      break;
    }

    pToolData->strName            = strNames[i];
    pToolData->uID                = uIDs[i];
    pToolData->uCmdID             = uCmdIDs[i];
    pToolData->bNeedMouseInput    = FALSE;
    pToolData->hBitmap            = NULL;
    pToolData->hBitmap2K          = NULL;

    arrTools->push_back(pToolData);
  }

  if(dwError != ERROR_SUCCESS)
  {
    for_each(arrTools->begin(), arrTools->end(),
      [](CToolData* pToolData) { _DELETE(pToolData); });
    _DELETE(arrTools);
    return dwError;
  }

  _TRY_BEGIN  
  m_mapToolGroups[IDS_OD_TOOL_GROUP] = arrTools;
  _CATCH_ALL
  for_each(arrTools->begin(), arrTools->end(),
  [](CToolData* pToolData) { _DELETE(pToolData); });
  _DELETE(arrTools);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  return dwError;
}

DWORD CToolDataAdmin::createETCToolData(BOOL bLoad2K)
{
  UINT uCmdIDs[] = 
  {
    TV_CMD_VIEW_DICOM_HEADER,         //view dicom header
    TV_CMD_SETTING,                   //setting
    TV_CMD_ABOUT                      //about
  };

  UINT uIDs[] =
  {
    IDC_BTN_ETC_DICOM_HEADER,         //view dicom header
    IDC_BTN_ETC_SETTING,              //setting
    IDC_BTN_ETC_ABOUT                 //about
  };

  BOOL bNeedMouseInputs[] =
  {
    TRUE,         //view dicom header
    FALSE,          //setting
    FALSE           //about
  };

  CString strNames[] =
  {
    _T("DICOM Info"),                 //view dicom header
    _T("Setting"),                    //setting
    _T("About")                       //about
  };

  std::vector<CToolData*>* arrTools = NULL;
  _TRY_ALLOC(arrTools, std::vector<CToolData*>);
  if(arrTools == NULL)
    return ERROR_NOT_ENOUGH_MEMORY;

  int nCount = sizeof(uIDs) / sizeof(UINT);
  _TRY_BEGIN
  arrTools->reserve(nCount);
  _CATCH_ALL
  _DELETE(arrTools);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  DWORD dwError = ERROR_SUCCESS;
  for(int i = 0; i < nCount; i++)
  {
    CToolData* pTool = NULL;
    _TRY_ALLOC(pTool, CToolData);
    if(pTool == NULL)
    {
      dwError = ERROR_NOT_ENOUGH_MEMORY;
      break;
    }

    pTool->strName          = strNames[i];
    pTool->uID              = uIDs[i];
    pTool->uCmdID           = uCmdIDs[i];
    pTool->bNeedMouseInput  = bNeedMouseInputs[i];
    pTool->hBitmap          = NULL;
    pTool->hBitmap2K        = NULL;

    arrTools->push_back(pTool);
  }

  if(dwError != ERROR_SUCCESS)
  {
    for_each(arrTools->begin(), arrTools->end(),
      [](CToolData* pToolData) { _DELETE(pToolData); });
    _DELETE(arrTools);
    return dwError;
  }

  _TRY_BEGIN
  m_mapToolGroups[IDS_ETC_TOOL_GROUP] = arrTools;
  _CATCH_ALL
  for_each(arrTools->begin(), arrTools->end(),
    [](CToolData* pToolData) { _DELETE(pToolData); });
  _DELETE(arrTools);
  return ERROR_NOT_ENOUGH_MEMORY;
  _CATCH_END

  return dwError;
}

void CToolDataAdmin::destroyToolData()
{
  for(auto it = m_mapToolGroups.begin(); it != m_mapToolGroups.end(); it++)
  {
    for_each(it->second->begin(), it->second->end(),
      [](CToolData* pToolData) { _DELETE(pToolData); });
    _DELETE(it->second);
  }
  m_mapToolGroups.clear();
}

DWORD CToolDataAdmin::createDefaultToolboxData(const TCHAR* pszGroupName, 
                                               CToolboxData*& pOutToolboxData) const
{
  if(pszGroupName == NULL)
    return ERROR_INVALID_PARAMETER;

  auto mapit = m_mapToolGroups.find(pszGroupName);
  if(mapit == m_mapToolGroups.end())
    return ERROR_INVALID_PARAMETER;

  CToolboxData* pDefaultToolboxData = NULL;
  _TRY_ALLOC(pDefaultToolboxData, CToolboxData);
  if(pDefaultToolboxData == NULL)
    return ERROR_NOT_ENOUGH_MEMORY;

  pDefaultToolboxData->setName(pszGroupName);

  std::vector<CToolData*>* pTools = mapit->second;
  DWORD dwError = ERROR_SUCCESS;
  for(auto i = pTools->begin(); i != pTools->end(); i++)
  {
    dwError = pDefaultToolboxData->addToolData((*i));
    if(dwError != ERROR_SUCCESS)
      break;
  }

  if(dwError != ERROR_SUCCESS)
  {
    _DELETE(pDefaultToolboxData);
    return dwError;
  }

  pOutToolboxData = pDefaultToolboxData;
  return ERROR_SUCCESS;
}